using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

namespace ScreenSnapper
{
    enum BitmapTcpResponseType
    {
        None,
        JpgFile,
        PngFile
    }

    class BitmapTcpResponse
    {
        private BitmapTcpResponseType _responseType;
        public BitmapTcpResponseType ResponseType
        {
            get
            {
                return _responseType;
            }
        }
        private byte[] _data;
        public byte[] Data
        {
            get
            {
                return _data;
            }
        }

        public BitmapTcpResponse(BitmapTcpResponseType responseType,
            byte[] data)
        {
            _responseType = responseType;
            _data = data;
        }
    }

    class BitmapTcpClient
    {
        public BitmapTcpClient()
        {
        }

        public BitmapTcpResponse FetchBitmapData(string server)
        {
            TcpClient client = new TcpClient();
            BitmapTcpResponse response = null;
            try
            {
                client.Connect(server, BitmapTcpServer.PORT);

                NetworkStream stream = client.GetStream();

                BitmapTcpResponseType responseType = DownloadResponseType(stream);
                byte[] data = null;

                if (BitmapTcpResponseType.None != responseType)
                {
                    data = DownloadBytes(stream);
                }

                response = new BitmapTcpResponse(responseType, data);
            }
            catch (Exception /*e*/)
            {
            }
            finally
            {
                client.Close();
            }

            return response;
        }

        private BitmapTcpResponseType DownloadResponseType(NetworkStream stream)
        {
            byte[] responseData = new byte[3];
            stream.Read(responseData, 0, 3);
            string response = ByteArrayToString(responseData);
            switch (response)
            {
                case "JPG": return BitmapTcpResponseType.JpgFile;
                case "PNG": return BitmapTcpResponseType.PngFile;
                default: return BitmapTcpResponseType.None;
            }
        }

        private string ByteArrayToString(byte[] responseData)
        {
            char[] charArray = new char[responseData.Length];
            for (int i = 0; i < responseData.Length; ++i)
            {
                charArray[i] = (char)responseData[i];
            }
            return new string(charArray);
        }

        private byte[] DownloadBytes(NetworkStream stream)
        {
            byte[] lengthData = new byte[4];
            stream.Read(lengthData, 0, 4);
            long length = ByteArrayToLong(lengthData);
            byte[] data = new byte[length];
            int offset = 0;
            int readBytes = 0;
            bool first = true;
            while (first || readBytes > 0)
            {
                readBytes = stream.Read(data, offset, data.Length - offset);
                offset += readBytes;
                first = false;
            }
            return data;
        }

        private long ByteArrayToLong(byte[] lengthData)
        {
            long val = ((long)lengthData[0]) +
                (((long)lengthData[1]) << 8) +
                (((long)lengthData[2]) << 16) +
                (((long)lengthData[3]) << 24);
            return val;
        }
    }
}
